創建一個React資料夾名為client
npx create-react-app client
將client放進sample(上一章的後端資料夾)裡,如下
在client裡下載module(要在client資料夾裡)
npm install react-router-dom axios
client檔案結構如下
將導覽列作為component
import React from "react";
import { Link } from "react-router-dom";
const Nav = () => {
return (
<nav>
<h2>台北101導覽</h2>
<ul>
<li>
<Link to="/">Homepage</Link>
</li>
<li>
<Link to="/Contact">Login</Link>
</li>
</ul>
</nav>
);
};
export default Nav;
透過axios讓react(前端)連接到Node.js(後端)
import axios from "axios";
const API_URL = "http://localhost:8080/api/contact";
class AuthService {
contact(name, email, phone, need) {
return axios.post(API_URL + "/method", {
name,
email,
phone,
need,
});
}
}
export default new AuthService();
首頁
import React from "react";
import Picture from "../pictures/one.jpg";
import Picture2 from "../pictures/two.jpeg";
const Home = () => {
return (
<main className="body">
<section className="up">
<img src={Picture} alt="封面" />
<h1 className="two" id="go">
台北最美的風景
</h1>
<a href="#introduce">開始導覽</a>
</section>
<section className="down" id="introduce">
<div className="left">
<h1 className="blue">導覽</h1>
<p>
台北101是位於臺灣臺北市信義區的摩天大樓,樓高510公尺,地上101層、地下5層,自落成以來即成為台北重要地標與觀光景點之一。台北101是台灣第一高樓、以及唯一樓層超過100層的建築物,曾於2004年12月1日至2010年1月7日間擁有世界第一高樓的紀錄。目前為世界第十一高樓,也是數一數二高的綠建築。大樓內擁有全球第二大、全球唯二開放給遊客觀賞的巨型阻尼器。標高460公尺的101樓上方之觀景台為全球最高的戶外屋頂觀景步道。
</p>
<p>
台北101座落於臺北市的中心商業區——信義計畫區,最初是為了配合臺灣政府的亞太營運中心政策而籌建的金融服務設施,後轉變成綜合性的商辦建築。原本計畫興建5棟建築,後來改為合併成一座摩天大廈,建築高度最終則提升至509.2公尺,以成為當時之世界第一高樓為目標。
</p>
<p>
台北101的地上樓層有101樓,若包括頂部塔尖內不開放遊客參觀的5層樓則有106樓,地下尚有5層樓。根據CTBUH的4項分類建築物高度判斷法,台北101啟用時在其中3項標準中皆為全世界最高的摩天大樓。
</p>
</div>
<div className="right">
<img src={Picture2} alt="101照片" />
</div>
</section>
</main>
);
};
export default Home;
聯絡表單
import React, { useState } from "react";
import AuthService from "../services/auth.service";
const Contact = () => {
let [name, setName] = useState("");
let [email, setEmail] = useState("");
let [phone, setPhone] = useState("");
let [need, setNeed] = useState("");
let [message, setMessage] = useState("");
const handleChangeName = (e) => {
setName(e.target.value);
};
const handleChangeEmail = (e) => {
setEmail(e.target.value);
};
const handleChangePhone = (e) => {
setPhone(e.target.value);
};
const handleChangeNeed = (e) => {
setNeed(e.target.value);
};
const handleContact = () => {
AuthService.contact(name, email, phone, need)
.then(() => {
window.alert("Contact succeeds.");
})
.catch((error) => {
console.log(error.response);
setMessage(error.response.data);
});
};
return (
<main>
<section className="contact">
<section className="contactWord">
<h2>我的電話: 0900-123-456</h2>
<h2>我的Email : 123456@gmail.com</h2>
<h2>方便聯絡時間 : 周一至周六早上八點到晚上七點</h2>
<h2>其他聯絡方式 : 臉書、IG</h2>
</section>
<div className="line"></div>
<section className="form">
<div className="form2">
<div>
<label for="name">姓名:</label>
<input
onChange={handleChangeName}
type="text"
id="name"
name="name"
/>
</div>
<br />
<div>
<label for="email">郵件:</label>
<input
onChange={handleChangeEmail}
type="email"
id="email"
name="email"
/>
</div>
<br />
<div>
<label for="phone">電話:</label>
<input
onChange={handleChangePhone}
type="text"
id="phone"
name="phone"
/>
</div>
<br />
<div>
<label for="need">需求:</label>
<textarea
onChange={handleChangeNeed}
name="need"
id="need"
rows="10"
></textarea>
</div>
<br />
<button onClick={handleContact} type="submit">
提交表單
</button>
<div>{message && <div className="error">{message}</div>}</div>
</div>
</section>
</section>
</main>
);
};
export default Contact;
import React, { useState } from "react";
import Nav from "./components/Nav";
import Home from "./pages/Home";
import Contact from "./pages/Contact";
import { BrowserRouter, Routes, Route } from "react-router-dom";
import "./styles/style.css";
function App() {
return (
<div className="App">
<BrowserRouter>
<Nav />
<Routes>
<Route path="/" element={<Home />} />
<Route path="/Contact" element={<Contact />} />
</Routes>
</BrowserRouter>
</div>
);
}
export default App;
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
* {
margin: 0;
padding: 0;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
a {
text-decoration: none;
}
nav {
background-color: #00b3b9;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-pack: justify;
-ms-flex-pack: justify;
justify-content: space-between;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
-ms-flex-wrap: wrap;
flex-wrap: wrap;
position: -webkit-sticky;
position: sticky;
top: 0px;
z-index: 3;
-webkit-box-shadow: 3px 1px 5px 4px #5e5e5e;
box-shadow: 3px 1px 5px 4px #5e5e5e;
}
nav h2 {
font-size: 2rem;
margin-left: 2rem;
color: white;
}
nav ul {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-pack: end;
-ms-flex-pack: end;
justify-content: flex-end;
margin-right: 3rem;
list-style-type: none;
}
nav ul li {
padding: 0.5rem 1rem;
}
nav ul li a {
font-size: 1.5rem;
color: white;
}
main section.up {
position: relative;
}
main section.up img {
z-index: -1;
width: 100%;
height: 100vh;
}
main section.up h1.two {
position: absolute;
bottom: 82vh;
right: 15vw;
font-size: 3.5rem;
color: white;
}
main section.up a {
position: absolute;
bottom: 20vh;
right: 22vw;
font-size: 2rem;
text-decoration: none;
background-color: #00b3b9;
color: black;
border-radius: 10%;
padding: 1rem 1.1rem;
}
main section.down {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-ms-flex-wrap: wrap;
flex-wrap: wrap;
padding-bottom: 5rem;
padding-top: 3rem;
}
main section.down div.left {
-webkit-box-flex: 3;
-ms-flex: 3 1 500px;
flex: 3 1 500px;
}
main section.down div.left h1 {
padding-left: 3rem;
font-size: 2rem;
}
main section.down div.left p {
padding: 2rem 3rem;
}
main section.down div.right {
-webkit-box-flex: 1;
-ms-flex: 1 1 200px;
flex: 1 1 200px;
}
main section.down div.right img {
width: 20vw;
height: 60vh;
margin-left: 3rem;
}
main section.contact {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-ms-flex-wrap: wrap;
flex-wrap: wrap;
-ms-flex-pack: distribute;
justify-content: space-around;
padding: 3rem;
}
main section.contact section.contactWord {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
-webkit-box-pack: space-evenly;
-ms-flex-pack: space-evenly;
justify-content: space-evenly;
}
main section.contact div.line {
width: 4px;
background-color: #00fff0;
}
main section.contact section.form {
margin-left: 3rem;
}
main section.contact section.form div.form2 {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
height: 70vh;
}
main section.contact section.form div.form2 div {
font-size: 1.2rem;
}
main section.contact section.form div.form2 div input,
main section.contact section.form div.form2 div textarea {
width: 30vw;
margin: 1rem 1.5rem;
background-color: #c4c4c4;
}
main section.contact section.form div.form2 div textarea {
vertical-align: top;
}
main section.contact section.form div.form2 button {
-ms-flex-item-align: center;
-ms-grid-row-align: center;
align-self: center;
width: 8rem;
background-color: #00fff0;
font-size: 1.2rem;
padding: 0.5rem 0rem;
border-radius: 10px;
}
@media screen and (max-width: 850px) {
nav h2 {
margin-left: 1rem;
}
main.body section.up img {
width: 100%;
height: 100%;
z-index: -1;
}
main.body section.up h1.two {
font-size: 1.2rem;
bottom: 23vh;
right: 5vw;
}
main.body section.up a {
font-size: 0.5rem;
bottom: 5vh;
right: 13vw;
padding: 0.5rem 0.6rem;
}
main.body section.down {
padding-bottom: 0rem;
}
main.body section.down div.left h1 {
font-size: 1.5rem;
}
main.body section.down div.right img {
width: 60vw;
height: 50vh;
margin-left: 5rem;
}
}
/*# sourceMappingURL=style.css.map */
最後運行2個server做執行
1.client資料夾
npm start
2.sample資料夾
node index.js
恭喜你!現在整個全端網頁都製作完成了!
【明天將會進行上架的部分】